﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using System.Xml.Serialization;

namespace Tomahawk.Runtime.Components
{
    public abstract class OverlayParameters
    {
        [XmlAttribute("Enabled")]
        public bool enabled = false;

        [XmlAttribute("X")]
        public float X = 22;

        [XmlAttribute("Y")]
        public float Y = 22;
    }

    public abstract class OverlayComponent : DrawableGameComponent
    {
        #region Fields
        private ContentManager content;
        private SpriteBatch spriteBatch;
        private SpriteFont spriteFont;
        private Vector2 basePos = Vector2.Zero;
        private Vector2 cursor = Vector2.Zero;
        private BasicEffect basicEffect = null;
        private VertexDeclaration lineVertexDeclaration = null;
        #endregion

        #region Initialization
        protected OverlayComponent(Vector2 basePos, Game game)
            : base(game)
        {
            this.basePos = basePos;
            content = new ContentManager(game.Services);
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            spriteFont = content.Load<SpriteFont>(@"Tomahawk.Content\Debug\DebugWriter");
            basicEffect = new BasicEffect(GraphicsDevice, null);
            lineVertexDeclaration = new VertexDeclaration(GraphicsDevice, VertexPositionColor.VertexElements);
        }

        protected override void UnloadContent()
        {
            content.Unload();
        }
        #endregion

        #region Update
        protected abstract void OnUpdate(GameTime gameTime);

        public sealed override void Update(GameTime gameTime)
        {
            OnUpdate(gameTime);
        }
        #endregion

        #region Draw
        public void DrawGrid(Matrix worldMatrix, float size, int divisions)
        {
            int gridLines = 2 * divisions + 1;

            // Cuadrícula en el plano XZ
            VertexPositionColor[] grid = new VertexPositionColor[4 * gridLines];

            Vector3 start = size * (Vector3.Left + Vector3.Forward);
            Vector3 end = size * (Vector3.Left + Vector3.Backward);
            Vector3 delta = 2 * size * Vector3.Right / divisions;

            for (int idx = 0; idx < gridLines; idx += 2)
            {
                grid[idx + 0] = new VertexPositionColor(Vector3.Transform(start, worldMatrix), Color.LightGray);
                grid[idx + 1] = new VertexPositionColor(Vector3.Transform(end, worldMatrix), Color.LightGray);
                start += delta;
                end += delta;
            }

            start = size * (Vector3.Left + Vector3.Forward);
            end = size * (Vector3.Right + Vector3.Forward);
            delta = 2 * size * Vector3.Backward / divisions;

            for (int idx = gridLines + 1; idx <= 2 * gridLines; idx += 2)
            {
                grid[idx + 0] = new VertexPositionColor(Vector3.Transform(start, worldMatrix), Color.LightGray);
                grid[idx + 1] = new VertexPositionColor(Vector3.Transform(end, worldMatrix), Color.LightGray);
                start += delta;
                end += delta;
            }

            // Ejes de la cuadrícula
            VertexPositionColor[] axes = new VertexPositionColor[4];

            axes[0] = new VertexPositionColor(Vector3.Transform(size * Vector3.Left, worldMatrix), Color.Red);
            axes[1] = new VertexPositionColor(Vector3.Transform(size * Vector3.Right, worldMatrix), Color.Red);
            axes[2] = new VertexPositionColor(Vector3.Transform(size * Vector3.Forward, worldMatrix), Color.Blue);
            axes[3] = new VertexPositionColor(Vector3.Transform(size * Vector3.Backward, worldMatrix), Color.Blue);

            // Dibujado de la rejilla
            basicEffect.World = worldMatrix;
            basicEffect.View = Engine.Instance.CameraManager.ActiveCamera.ViewMatrix;
            basicEffect.Projection = Engine.Instance.CameraManager.ActiveCamera.ProjectionMatrix;
            basicEffect.VertexColorEnabled = true;

            GraphicsDevice.VertexDeclaration = lineVertexDeclaration;

            basicEffect.Begin();

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                    PrimitiveType.LineList,
                    grid,
                    0,
                    2 * gridLines);

                GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                    PrimitiveType.LineList,
                    axes,
                    0,
                    2);

                pass.End();
            }

            basicEffect.End();
        }

        protected void DrawString(float X, float Y, string text, ref Color color)
        {
            cursor.X = basePos.X + X;
            cursor.Y = basePos.Y + Y;
            spriteBatch.DrawString(spriteFont, text, cursor + Vector2.One, Color.Black);
            spriteBatch.DrawString(spriteFont, text, cursor, color);
        }

        protected abstract void OnDraw2D(GameTime gameTime);
        
        protected abstract void OnDraw3D(GameTime gameTime);

        public sealed override void Draw(GameTime gameTime)
        {
            cursor.X = 32;
            cursor.Y = 22;

            OnDraw3D(gameTime);

            spriteBatch.Begin();
            OnDraw2D(gameTime);
            spriteBatch.End();

            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.RenderState.AlphaBlendEnable = false;
            GraphicsDevice.RenderState.AlphaTestEnable = false;
        }
        #endregion
    }
}
